package com.ptswitch.material.pages.base;

import java.util.Collections;
import java.util.List;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.tapestry5.EventConstants;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.InjectPage;
import org.apache.tapestry5.annotations.SessionState;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.runtime.ComponentEventException;
import org.apache.tapestry5.services.Request;
import org.hxzon.project.AppRuntimeException;
import org.hxzon.util.ConcurrentUtil;
import org.hxzon.util.EMailUtil;
import org.hxzon.util.EMailUtil.EMail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ptswitch.material.model.common.LoginInfo;
import com.ptswitch.material.model.common.Uzer;
import com.ptswitch.material.model.security.Permission;
import com.ptswitch.material.model.security.Role;
import com.ptswitch.material.pages.visitor.Login;
import com.ptswitch.material.service.HLogService;
import com.ptswitch.material.service.LoginInfoService;
import com.ptswitch.material.service.RoleService;
import com.ptswitch.material.service.UserService;
import com.ptswitch.material.util.AuthenticationException;
import com.ptswitch.material.util.Messages;
import com.ptswitch.material.util.WebUtil;
import com.ptswitch.material.util.security.PermissionCheckUtil;

@Import(stylesheet = { "context:css/screen.css", "context:css/ddcolortabs.css", //
        "context:css/jquery-ui-1.10.2.custom.css", "context:css/hxzon.head.css" }, //
library = { "context:js/jquery-ui-1.10.2.custom.js",//"context:js/jquery-1.7.2.js","context:js/jquery-ui-1.8.18.custom.js",
        "context:js/hxzon.jquery.dropdownMenu.js", "context:js/hxzon.tapestry.js",//
        "context:js/hxzon.jquery.panel.js", "context:js/hxzon.jquery.tree.js",//
        "context:js/hxzon.head.js" })
public class PageBase {
    private static final Logger logger = LoggerFactory.getLogger(PageBase.class);

    @Inject
    private HttpServletRequest servletRequest;
    @Inject
    private Request request;
    @Inject
    @Symbol(SymbolConstants.CONTEXT_PATH)
    private String contextPath;
    @Inject
    private HLogService hlogSer;
    @Inject
    private UserService userSer;
    @Inject
    private RoleService roleSer;
    @Inject
    private LoginInfoService loginInfoSer;
    @InjectPage
    private Login login;
    //
    @SessionState
    private Messages message;
    private Uzer visitor;
    private static final LoginInfo GuessLoginInfo = new LoginInfo();
    static {
        Uzer guess = new Uzer();
        guess.setUsername(Uzer.Username_Guess);
        GuessLoginInfo.setUser(guess);
    }

    // If there is no exception event handler, or the exception event handler
    // returns null (or is void), then then the exception will be passed
    // to the RequestExceptionHandler service
    Object onException(Throwable cause) {
        logger.error("root:" + cause.getClass(), cause);
        // ComponentEventException
//        while (cause instanceof ComponentEventException || cause instanceof OldRuntimeException) {
//            cause = cause.getCause();
//            logger.error("cause:" + cause.getClass());
//        }
        String eventType = null;
        while (cause instanceof ComponentEventException) {
            eventType = ((ComponentEventException) cause).getEventType();
            cause = cause.getCause();
        }
        if (cause instanceof AuthenticationException) {
            setMessage(cause.getMessage());
            return login.withInit(getWebUrl() + request.getPath());
        } else if (cause instanceof AppRuntimeException) {
            setMessage(cause.getMessage());
        } else {
        }
        if (EventConstants.ACTIVATE.equals(eventType)) {
            return null;
        }
        return this;
    }

    // h log
    public void hlog(String overview, Object o) {
        hlogSer.log(getLoginInfo().getUser(), overview, o);
    }

    public void hlog(String overview) {
        hlogSer.log(getLoginInfo().getUser(), overview);
    }

    //send email
    public void sendEMail(final EMail email) {
        ConcurrentUtil.execute(new Runnable() {
            @Override
            public void run() {
                EMailUtil.sendAndWait(email);
//				if (sendOk) {
//					setMessage("邮件发送成功");
//				} else {
//					setMessage("邮件发送失败");
//				}
            }
        });
    }

    // server info
    private static String webUrl;

    public String getWebUrl() {
        if (webUrl == null) {
            // host : port /web
//			webUrl = "http://" + servletRequest.getLocalAddr() + ":" + servletRequest.getLocalPort() + servletRequest.getContextPath();
            webUrl = "http://" + request.getServerName() + ":" + request.getLocalPort() + contextPath;
            logger.info("web url:" + webUrl);
        }
        return webUrl;
    }

    // get and set
    public String getMessage() {
        return message.read();
    }

    public void setMessage(String message) {
        this.message.write(message);
    }

    public Uzer getVisitor() {
        if (visitor == null) {
            visitor = getLoginInfo().getUser();
        }
        return visitor;
    }

    public LoginInfo getLoginInfo() {
        Cookie cookies[] = servletRequest.getCookies();
        LoginInfo cookie = WebUtil.getLoginInfoCookie(cookies);
        LoginInfo loginInfo = loginInfoSer.findByUsernameAndLoginToken(cookie.getUsername(), cookie.getId());
        if (loginInfo == null) {
            loginInfo = GuessLoginInfo;
            logger.info("login guest");
        } else {
            loginInfo.setUser(userSer.findByUsername(loginInfo.getUsername()));
            logger.info("cookie login:{}", loginInfo.getUser());
        }
        return loginInfo;
    }

    public String getBackUrl() {
//		return servletRequest.getHeader("Referer");
        return request.getHeader("Referer");
    }

    //permission check
    protected List<Role> appendRoleToVisitor(Uzer visitor) {
        return Collections.emptyList();
    }

    protected final List<Role> appendThisRole(Role... roles) {
        return roleSer.findRoles(roles);
    }

    protected final List<Role> appendThisRole(List<Role> roles) {
        return roleSer.findRoles(roles);//TODO:search every time
    }

    public final boolean checkPermitted(Permission require) {
        return checkPermitted(require.getPermissionName(), true);
    }

    public final boolean checkPermitted(String require) {
        return checkPermitted(require, true);
    }

    public final boolean checkPermitted(String require, boolean throwException) {
        Uzer visitor = this.getVisitor();
        List<Role> appendRole = appendRoleToVisitor(visitor);
        appendRole = appendThisRole(appendRole);
        if (PermissionCheckUtil.checkPermitted(require, appendRole)) {
            return true;
        }
        List<Role> userRoles = visitor.getRoles();
        if (PermissionCheckUtil.checkPermitted(require, userRoles)) {
            return true;
        }
        if (throwException) {
            throw new AuthenticationException("你没有操作权限");
        } else {
            return false;
        }
    }

}
